/**
 * Copyright (c) 2016-2019 HBZH All rights reserved.
 *
 * <p>https://www.com
 */
package com.demo.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.common.enums.TokenTypeEnum;
import com.demo.common.exception.RRException;
import com.demo.config.cache.ObjectCacheConfig;
import com.demo.config.token.TokenGenerator;
import com.demo.modules.redis.SysTokenRedis;
import com.demo.modules.sys.dao.SysUserTokenDao;
import com.demo.modules.sys.entity.SysUserTokenEntity;
import com.demo.modules.sys.service.SysUserTokenService;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Service("sysUserTokenService")
public class SysUserTokenServiceImpl extends ServiceImpl<SysUserTokenDao, SysUserTokenEntity>
        implements SysUserTokenService {

    @Autowired
    private SysTokenRedis sysTokenRedis;

    /*sys*/
    @Value("${login.sys.expire}")
    private int sysExpire;

    @Value("${login.sys.multi}")
    private boolean sysMulti;
    /*app*/

    @Value("${login.app.expire}")
    private int appExpire;

    @Value("${login.app.multi}")
    private boolean appMulti;

    /*other*/
    @Value("${login.other.expire}")
    private int otherExpire;

    @Value("${login.other.multi}")
    private boolean otherMulti;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SysUserTokenEntity createToken(long userId, String tokenType) {
        // 生成一个token
        String token = TokenGenerator.generateValue();

        // 过期时间
        Integer expire = null;
        // 是否允许多端登陆
        boolean multi = false;
        // 判断token类型
        if (TokenTypeEnum.SYS.getValue().equals(tokenType)) {
            expire = sysExpire;
            multi = sysMulti;
        } else if (TokenTypeEnum.APP.getValue().equals(tokenType)) {
            expire = appExpire;
            multi = appMulti;
        } else {
            expire = otherExpire;
            multi = otherMulti;
        }
        if (expire == null) {
            throw new RRException("Token过期时间为空");
        }
        //加半小时
        LocalDateTime expireTime = LocalDateTime.now();
        expireTime = expireTime.plusMinutes(expire);

        // 判断是否生成过token
        LambdaQueryWrapper<SysUserTokenEntity> query = new LambdaQueryWrapper<>();
        query.eq(SysUserTokenEntity::getUserId, userId);
        query.eq(SysUserTokenEntity::getTokenType, tokenType);
        SysUserTokenEntity tokenEntity = this.getOne(query);
        // 无token
        if (tokenEntity == null) {
            tokenEntity = new SysUserTokenEntity();
            tokenEntity.setUserId(userId);
            tokenEntity.setToken(token);
            tokenEntity.setTokenType(tokenType);
            tokenEntity.setUpdateTime(LocalDateTime.now());
            tokenEntity.setExpireTime(expireTime);

            // 保存token
            this.save(tokenEntity);
        } else {
            // 如果token过期
            if (LocalDateTime.now().isAfter(tokenEntity.getExpireTime())) {
                tokenEntity.setToken(token);
            }
            // 如果不允许多端登陆，重置token
            if (!multi) {
                tokenEntity.setToken(token);
            }

            tokenEntity.setUpdateTime(LocalDateTime.now());

            tokenEntity.setExpireTime(expireTime);

            // 更新token
            this.updateById(tokenEntity);
        }
        //缓存
        ObjectCacheConfig.tokenCache.put(tokenEntity.getToken(), tokenEntity);
        //redis 缓存
        sysTokenRedis.saveOrUpdate(tokenEntity);
        return tokenEntity;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void logout(long userId, String tokenType) {
        // 是否允许多端登陆
        boolean multi = false;
        // 判断token类型
        if (TokenTypeEnum.SYS.getValue().equals(tokenType)) {
            multi = sysMulti;
        } else if (TokenTypeEnum.APP.getValue().equals(tokenType)) {
            multi = appMulti;
        } else {
            multi = otherMulti;
        }

        if (!multi) {
            // 生成一个token
            String token = TokenGenerator.generateValue();

            // 获取token
            SysUserTokenEntity tokenEntity =
                    this.getOne(
                            new LambdaQueryWrapper<SysUserTokenEntity>()
                                    .eq(SysUserTokenEntity::getUserId, userId)
                                    .eq(SysUserTokenEntity::getTokenType, tokenType));

            // 修改token
            tokenEntity.setToken(token);
            this.updateById(tokenEntity);
            //清楚缓存
            ObjectCacheConfig.tokenCache.remove(tokenEntity.getToken());
            //清楚 redis 缓存
            sysTokenRedis.delete(tokenEntity.getToken());
        }
        SecurityUtils.getSubject().logout();
    }
}
